package colin.project.sso.server.common.event.aspect;

import cn.hutool.core.util.ArrayUtil;
import colin.project.sso.server.business.observer.PubOperationEvent;
import colin.project.sso.server.business.observer.enums.OperationEventEnums;
import colin.project.sso.server.common.event.annotation.OperationEvent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Author joker
 * @Title OperationEventAspect
 * @Description
 * @Date 2019/5/19 10:54 PM
 * @Since
 * @Version 1.0.0
 */
@Component
@Aspect
public class OperationEventAspect extends BasicAspect implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Pointcut(value = "execution(* colin.project.sso.server.business.service..(..))")
    public void joinpoint() {

    }

    @Before(value = "joinpoint()")
    public void before(JoinPoint jp) {
        Method targetMethod = super.getProxyMethod(jp);
        Annotation[] targetAnnos = targetMethod.getDeclaredAnnotations();
        if (null == targetAnnos || targetAnnos.length == 0) {
            return;
        }
        boolean existsTarget = ArrayUtil.contains(targetAnnos, OperationEvent.class);
        if (existsTarget) {
            OperationEvent operationEvent = targetMethod.getDeclaredAnnotation(OperationEvent.class);
            OperationEventEnums[] eventEnums = operationEvent.event();

            for (OperationEventEnums operationEventEnum : eventEnums) {
                PubOperationEvent pubOperationEvent = new PubOperationEvent(operationEventEnum, jp.getArgs());
                this.applicationContext.publishEvent(pubOperationEvent);
            }
        }
    }

    /**
     * Set the ApplicationContext that this object runs in.
     * Normally this call will be used to initialize the object.
     * <p>Invoked after population of normal bean properties but before an init callback such
     * as {@link InitializingBean#afterPropertiesSet()}
     * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
     * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
     * {@link MessageSourceAware}, if applicable.
     *
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws ApplicationContextException in case of context initialization errors
     * @throws BeansException              if thrown by application context methods
     * @see BeanInitializationException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
